import traceback
from flask import Blueprint, request, abort
from flask_restful import reqparse, inputs, Resource, Api, fields, marshal_with
from ....models.database import db, auto_commit
from ....decorator.consolejwt import console_token
from ...res import output_json
from ....models.console.role import Role
from ....models.console.roleuser import RoleUser
from ....models.console.rolepriv import RolePriv
from ....models.console.menu import Menu
from ....libs.unit import abort_msg
import pandas as pd

role = Blueprint('role', __name__, url_prefix='/c-api/role')
api = Api(role)

# 统一封装 API 返回值
@api.representation('application/json')
def out_json(data, code, headers=None):
    return output_json(data, code, headers=None)


# 封装返回的数据格式
resource_list = {
    'count': fields.Integer,
    'list': fields.List(fields.Nested({
        'id': fields.Integer,
        'name': fields.String,
        'status': fields.String
    }))
}

class ListRole(Resource):
    @console_token
    @marshal_with(resource_list, envelope='resource')
    def get(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('page', type=int,
                            help='页码必须填写', location=['form', 'args'], required=True, action='store')
        args = parser.parse_args()
        page = args.get('page')
        with auto_commit():
            lists = Role.query.order_by(Role.id.desc()).paginate(
                page, per_page=10, error_out=False)
            c = {'count': lists.total, 'list': lists.items}
        return c


# 封装返回的数据格式
resource_detail = {
    'id': fields.Integer,
    'name': fields.String,
    'status': fields.String
}


class DetailRole(Resource):
    @console_token
    @marshal_with(resource_detail, envelope='resource')
    def get(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('role_id', type=int,
                            help='角色 ID 必须填写', location=['form', 'args'], required=True, action='store')
        args = parser.parse_args()
        with auto_commit():
            c = Role.query.filter(
                Role.id == args.get('role_id')).one()
        return c
        

class CreateRole(Resource):
    @console_token
    def post(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('name', type=str,
                            help='角色名称必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('status', type=inputs.positive,
                            help='状态标识必须填写', location=['form', 'args'], required=False, action='store', default=1)
        args = parser.parse_args()
        with auto_commit():
            c =  Role()
            c.name = args.get('name')
            c.display = args.get('status')
            db.session.add(c)
        return {'resource': ''}
        

class EditRole(Resource):
    @console_token
    def put(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('role_id', type=inputs.positive,
                            help='角色 ID 必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('name', type=str,
                            help='角色名称必须填写', location=['form', 'args'], required=True, action='store')
        parser.add_argument('status', type=inputs.positive,
                            help='状态标识必须填写', location=['form', 'args'], required=False, action='store', default=1)
        args = parser.parse_args()
        with auto_commit():
            c =  Role.query.filter(Role.id == args.get('role_id')).one()
            c.name = args.get('name')
            c.display = args.get('status')
        return {'resource': ''}


class DeleteRole(Resource):
    @console_token
    def delete(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('role_id', type=inputs.positive,
                            help='角色 ID 必须填写', location=['form', 'args'], required=True, action='store')
        args = parser.parse_args()
        with auto_commit():
            if args.get('role_id') == 1:
                return {'message': '超级管理员不能删除'}, 400
            # 先查有没有用户
            c = RoleUser.query.filter(RoleUser.role_id == args.get('role_id')).count()
            # print("#####", c)
            if c > 0:
                return {'message': '角色下有用户，请先给用户修改角色'}, 400
            Role.query.filter(Role.id == args.get('role_id')).delete()
            # 同时删除权限
            RoleUser.query.filter(RoleUser.role_id == args.get('role_id')).delete(synchronize_session = False)
            RolePriv.query.filter(RolePriv.role_id == args.get(
                'role_id')).delete(synchronize_session = False)
        return {'resource': ''}
        

# 更新角色权限，主要是为了显示后台菜单
class PrivRole(Resource):
    @console_token
    def get(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('role_id', type=inputs.positive,
                            help='角色 ID 必须填写', location=['form', 'args'], required=True, action='store')
        args = parser.parse_args()
        with auto_commit():
            p = RolePriv.query.filter(
                RolePriv.role_id == args.get('role_id')).all()
            m = Menu.query.order_by(Menu.sort.asc(), Menu.id.asc()).all()
            m = PrivRole.toTree(p, m, 0)
            plist = [{'id':p.id,'menu_id':p.menu_id} for p in p]
        return {'resource': {'priv': plist, 'menu': m}}
        
    # 转成树形菜单
    def toTree(priv,menu, pid):
        tree = []
        df_m = pd.DataFrame([(d.id, d.parentid, d.name, d.url) for d in menu],columns=['id', 'parentid', 'name', 'url'])
        df_p = pd.DataFrame([(d.menu_id) for d in priv], columns=['menu_id'])
        for i in menu:
            if i.parentid == pid:
                tmp = {'menu_id':i.id,'title':i.name,'expand':False}
                # 所有子菜单都选中的时候，此菜单选中checked，部分选中时selected
                child_count = df_m[df_m.parentid == i.id].shape[0]
                # 没有子菜单的时候，判断他本身
                if child_count == 0:
                    tmp['checked'] = True if df_p[df_p.menu_id == i.id].shape[0] > 0 else False
                tmp['children'] = PrivRole.toTree(priv, menu, i.id)
                tree.append(tmp)
        return tree
    
    # 更新权限菜单
    @console_token
    def put(self):
        # 请求验证
        parser = reqparse.RequestParser()
        parser.add_argument('role_id', type=inputs.positive,
                            help='角色 ID 必须填写', location=['form', 'args'], required=True, action='store')
        args = parser.parse_args()
        with auto_commit():
            rid = args.get('role_id')
            # 先删除
            RolePriv.query.filter(RolePriv.role_id == rid).delete(
                synchronize_session = False)
            ids = request.values.get('menu_id', default=[])
            allmenu = Menu.query.filter(Menu.id.in_(ids)).all()
            for i in allmenu:
                tmp = RolePriv(role_id=rid, menu_id=i.id, name=i.name,url=i.url, label=i.label)
                db.session.add(tmp)
        return {'resource':''}

api.add_resource(ListRole, '/list')
api.add_resource(DetailRole, '/detail')
api.add_resource(CreateRole, '/create')
api.add_resource(EditRole, '/edit')
api.add_resource(DeleteRole, '/delete')
api.add_resource(PrivRole, '/priv')
